package com.gillion.grule.client.utils;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.List;

public class Streams<T>
{
    private Iterable<T> source;

    private Streams(Iterable<T> source) {
        this.source = source;
    }

    public static <T> Streams<T> of(Iterable<T> source) {
        return new Streams<>(source);
    }

    public <R> Streams<R> map(Function<? super T, ? extends R> function) {
        Iterable<R> mapped = Iterables.transform(this.source, function);

        return new Streams(mapped);
    }

    public <R> R reduce(BiFunction<R, T> biFunction) {
        R r = null;
        for (T t : this.source) {
            r = biFunction.apply(r, t);
        }
        return r;
    }

    public <R> Streams<R> flatMap(Function<? super T, Iterable<R>> function) {
        Iterable<Iterable<R>> mapped = Iterables.transform(this.source, function);
        Iterable<R> flat = Iterables.concat(mapped);
        return new Streams(flat);
    }

    public Streams<T> filter(Predicate<T> predicate) {
        Iterable<T> mapped = Iterables.filter(this.source, predicate);
        return new Streams(mapped);
    }

    public void forEach(Closure<T> closure) {
        if (this.source != null) {
            for (T t : this.source) {
                closure.execute(t);
            }
        }
    }



    public List<T> collectToList() {
        return (this.source == null) ? new ArrayList<>() : Lists.newArrayList(this.source);
    }


    public final Streams<T> distinct() {
        return new Streams(Sets.newLinkedHashSet(this.source));
    }

    public final Iterable<T> get() {
        return this.source;
    }
}